﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using Kokomo.Mirror.CliMetadata;

namespace Kokomo.Mirror.PeFormat
{
	[Description("COR 2.0 Metadata Stream Header")]
	public class Cor20MetadataStreamHeader : PeHeaderStruct
	{
		[Browsable(false)]
		public int Reserved { get; private set; }

		public SmallVersion Version { get; private set; }

		[Browsable(false)]
		public byte HeapSizes { get; private set; }

		[DisplayName("Has large string heap")]
		public bool HasLargeStringHeap
		{
			get
			{
				return (this.HeapSizes & 0x01) != 0;
			}
			//set
			//{
			//    if (value)
			//        this.HeapSizes |= 0x01;
			//    else
			//        this.HeapSizes &= 0xFE;
			//}
		}

		[DisplayName("Has large GUID heap")]
		public bool HasLargeGuidHeap
		{
			get
			{
				return (this.HeapSizes & 0x02) != 0;
			}
		}

		[DisplayName("Has large blob heap")]
		public bool HasLargeBlobHeap
		{
			get
			{
				return (this.HeapSizes & 0x04) != 0;
			}
		}

		[Browsable(false)]
		public byte Reserved2 { get; private set; }

		private ulong _valid;

		[TypeConverter(typeof(HexConverter))]
		public ulong Valid
		{
			get { return this._valid; }
			private set
			{
				this._valid = value;

				int tableCount = 0;
				List<MetadataTableNumber> tableNumbers = new List<MetadataTableNumber>();
				for (int i = 0; i < (8 * 8); i++)
				{
					ulong mask = (ulong)1 << i;
					bool isSet = (value & mask) != 0;
					if (isSet)
					{
						tableNumbers.Add((MetadataTableNumber)i);
						tableCount++;
					}
				}

				this._tableCount = tableCount;
				this._tableNumbers = tableNumbers.ToArray();
			}
		}

		private MetadataTableNumber[] _tableNumbers;
		[Browsable(false)]
		public MetadataTableNumber[] TableNumbers
		{
			get
			{
				return this._tableNumbers;
			}
		}

		private int _tableCount;
		[DisplayName("Table count")]
		public int TableCount
		{
			get
			{
				return this._tableCount;
			}
		}

		[DisplayName("Sorted")]
		public ulong Sorted { get; private set; }

		[SerializedArray(ArrayLengthEncoding.ElementPrefixField, "TableCount")]
		[Browsable(false)]
		public uint[] Rows { get; private set; }

		[SerializerContextField(SerializerContextField.Position32)]
		[TypeConverter(typeof(HexConverter))]
		[DisplayName("Data offset")]
		public int DataOffset { get; private set; }
	}
}
